package com.pacvue.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import com.pacvue.annotation.RateLimiter;
import com.pacvue.exception.RateLimitException;
import com.pacvue.handler.RateLimitExceptionHandler;
import com.pacvue.handler.RateLimiterAcquireTokenHandler;
import com.pacvue.properties.RateLimiterProperties;
import com.pacvue.utils.SpELUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class RateLimiterAspect {

    private final RateLimiterProperties properties;
    private final RateLimiterAcquireTokenHandler rateLimiterAcquireTokenHandler;
    private final RateLimitExceptionHandler rateLimitExceptionHandler;


    @Around("@annotation(limiter)")
    public Object around(ProceedingJoinPoint pjp, RateLimiter limiter) throws Throwable {
        long startTime = System.currentTimeMillis();
        String methodName = pjp.getSignature().getName();
        String className = pjp.getTarget().getClass().getSimpleName();
        
        if (!properties.isEnabled()) {
            if (log.isDebugEnabled()) {
                log.debug("限流功能已禁用，直接执行方法 - {}.{}", className, methodName);
            }
            return pjp.proceed();
        }
        
        String key = SpELUtils.parse(limiter.key(), pjp);
        int capacity = limiter.capacity() > 0 ? limiter.capacity() : properties.getCapacity();
        double rate = limiter.rate() > 0 ? limiter.rate() : properties.getRate();
        int timeout = limiter.timeout() > 0 ? limiter.timeout() : properties.getTimeout();
        boolean retryEnabled = properties.getRetry().isEnabled();
        int retryTimes = properties.getRetry().getRetryTimes();
        int retryNum = 0;

        if (log.isDebugEnabled()) {
            log.debug("开始限流检查 - {}.{}, key: {}, capacity: {}, rate: {}, timeout: {}", 
                     className, methodName, key, capacity, rate, timeout);
        }

        while (true) {
            try {
                // 阻塞限流获取token
                rateLimiterAcquireTokenHandler.acquire(key, capacity, rate, timeout);
                
                long executionTime = System.currentTimeMillis() - startTime;

                if (log.isDebugEnabled()) {
                    log.debug("限流检查通过，执行方法 - {}.{}, key: {}, 等待时间: {}ms", 
                             className, methodName, key, executionTime);
                }
                
                return pjp.proceed();
                
            } catch (RateLimitException e) {
                if (!retryEnabled || retryNum >= retryTimes) {
                    long executionTime = System.currentTimeMillis() - startTime;
                    
                    if (log.isWarnEnabled()) {
                        log.warn("限流检查失败，请求被拒绝 - {}.{}, key: {}, 重试次数: {}, 总耗时: {}ms", 
                                className, methodName, key, retryNum, executionTime);
                    }
                    throw e;
                }
                retryNum++;
                if (log.isDebugEnabled()) {
                    log.debug("限流检查失败，准备重试 - {}.{}, key: {}, 重试次数: {}/{}", 
                             className, methodName, key, retryNum, retryTimes);
                }
                // 执行方法限流报错处理类， 默认使用指数退避算法
                rateLimitExceptionHandler.handle(e, key, retryNum);
            }
        }
    }
    

}
